
#include "eratosteneSieve.h"

using namespace LGFun;

EratosteneSieve::EratosteneSieve(UInt32 i_maxNum):
m_sieve(new bool[i_maxNum+1]),
m_size(i_maxNum+1),
m_ppTask(0)
{
    std::fill(m_sieve, m_sieve + m_size, true);
}



EratosteneSieve::EratosteneSieve(const EratosteneSieve& i_other):
m_sieve(new bool[i_other.m_size]),
m_size(i_other.m_size),
m_ppTask(0)
{
    //std::copy(i_other.m_sieve, i_other.m_sieve + i_other.m_size, m_sieve); //ugasoft: turbo unsafe with bool*, it's better to use memcpy
    memcpy(static_cast<void*>(m_sieve), static_cast<void*>(i_other.m_sieve), i_other.m_size*sizeof(bool));
}



EratosteneSieve::~EratosteneSieve()
{
    delete [] m_sieve;
}



EratosteneSieve& EratosteneSieve::operator=(const EratosteneSieve& i_other)
{
    delete [] m_sieve;
    m_size = i_other.m_size;
    m_sieve = new bool[m_size];
    //std::copy(i_other.m_sieve, i_other.m_sieve + i_other.m_size, m_sieve); //ugasoft: turbo unsafe with bool*, it's better to use memcpy
    memcpy(static_cast<void*>(m_sieve), static_cast<void*>(i_other.m_sieve), i_other.m_size*sizeof(bool));
    m_ppTask = 0;

    return *this;
}



bool EratosteneSieve::AddPerPrimeNumTask(AtPrimeNumberTask* i_task)
{
    if(i_task)
    {
        m_ppTask = i_task;
        return true;
    }
    
    return false;
}



void EratosteneSieve::Compute()
{
    if(!m_sieve[0])
        return; // Use the element 0 as already computed checking.

    if(m_ppTask)
        m_ppTask->Reset();

    m_sieve[0] = m_sieve[1] = false;
    m_sieve[2] = true;

    for(UInt32 i = 0; i < m_size; ++i)
    {
        if(m_sieve[i])
        {
            if(m_ppTask)
            {
                if(!m_ppTask->Update(i))
                {
                    m_sieve[0] = true; // Invalidation, computation not completed.
                    break;
                }
            }

            for(UInt32 j = i+i; j < m_size; j+=i)
                m_sieve[j] = false;
        }
    }
}



bool EratosteneSieve::IsPrime(UInt32 i_number) const
{
    if(m_sieve[0] || i_number >= m_size) 
        return false;
    else return m_sieve[i_number];
}
